#include "LecteurSymbole.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurSymbole::LecteurSymbole(string nomFich) :
        lc(nomFich), symCour("") {
    try {
        suivant(); // pour lire le premier symbole
    }
    catch (char const*) {
        throw; // ici, c'est "fichier non trouvé"
    }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurSymbole::suivant() {
    sauterSeparateurs();
    sauterCommentaire();
    // on est maintenant positionne sur le premier caractère d'un symbole
    ligne=lc.getLigne();
    colonne=lc.getColonne();
    bool error = false;
    do {
        try {
            symCour=Symbole(motSuivant()); // on reconstruit symCour avec le nouveau mot lu
	    error = false;
        }
        catch (char const*) {
            error = true;
        }
    } while (error);
}

////////////////////////////////////////////////////////////////////////////////
void LecteurSymbole::sauterSeparateurs() {
    while (lc.getCarCour()==' '  ||
            lc.getCarCour()=='\t' ||
            lc.getCarCour()=='\r' ||
            lc.getCarCour()=='\n')
        lc.suivant();

}

void LecteurSymbole::sauterCommentaire() {
    // Le caractere courant est le debut d'un commentaire '#'
    if (lc.getCarCour()=='#') {
        while (lc.getCarCour()!='\n') { // on avance jusqu'au bout de la ligne
            lc.suivant();
        }
        lc.suivant(); // et on passe a la ligne suivante
        sauterSeparateurs();
        sauterCommentaire();
    }
}

////////////////////////////////////////////////////////////////////////////////
string LecteurSymbole::motSuivant() {
    try {
        static string  s; // la chaine qui contiendra la valeur du symbole
        s="";
        if (isdigit(lc.getCarCour())) {
            // c'est le début d'un entier ou d'un reel
            bool point = false;
            do {
                if (lc.getCarCour()=='.') {
                    point = true; // on a rencontre un reel
                }
                else {
                    s=s+lc.getCarCour();
                    lc.suivant();
                }
            } while (isdigit(lc.getCarCour()) && !point); //si c'est plus un chiffre et que le point et passer alors ... si entier, c'est fini

            if (lc.getCarCour()=='.') { // sinon, on prend la seconde partie du reel
                s=s+lc.getCarCour();
                lc.suivant();
                while (isdigit(lc.getCarCour())) {
                    s=s+lc.getCarCour();
                    lc.suivant();
                }
            }
            if (s[s.size()-1]=='.') { // si on a un point sans chiffre deriere, c'est un reel avec *.0
                s=s+'0';
            }
        }
        else if (isOpBool(lc.getCarCour()))	{ // si c'est un =,!,<,>,
            s=s+lc.getCarCour();
            lc.suivant();
            if (isOpBool(lc.getCarCour())) { //alors on verifie si il y a une suite ==, <=, != ,>=
                s=s+lc.getCarCour();
                lc.suivant();
            }
        }
        else if (lc.getCarCour()=='"') {
            // c'est le début d'un string
            s=s+lc.getCarCour(); // premier guillemet
            lc.suivant();
            while (lc.getCarCour()!='"' && lc.getCarCour()!='\n') { // on peut inserer des caractere speciaux telque \n, \'\'
                if (lc.getCarCour() == '\\') { // on a peut etre un caract spec derriere
                    s=s+lc.getCarCour();
                    lc.suivant();
                    if (lc.getCarCour()=='"' && lc.getCarCour()!='\n') {
                        s=s+lc.getCarCour();
                        lc.suivant();
                    }
                }
                else { // sinon, on continu comme si derien
                    s=s+lc.getCarCour();
                    lc.suivant();
                }
            }
            if (lc.getCarCour()=='\n')
            {
                erreur("chaine de caractere");
            }
            s=s+lc.getCarCour(); // on ajoute le dernier guillemet
            lc.suivant();
        }
        else if (lc.getCarCour()=='\'') {
            // c'est le début d'un caract
            s=s+lc.getCarCour(); // apostraphe
            lc.suivant();
            s=s+lc.getCarCour(); // caract
            lc.suivant();
            if (lc.getCarCour()!='\'')
            {
                erreur("caractere");
            }
            s=s+lc.getCarCour(); // on ajoute le dernier apostrophe
            lc.suivant();
        }
        else if (isalpha(lc.getCarCour()))
            // c'est le début d'un mot
            do {
                s=s+lc.getCarCour();
                lc.suivant();
            } while (isalpha(lc.getCarCour())  ||
                     isdigit(lc.getCarCour()) ||
                     lc.getCarCour()=='_');
        else if (lc.getCarCour()!=EOF)
            // c'est un caractere special
        {
            s=lc.getCarCour();
            lc.suivant();
        }
        return s;
    }
    catch (char const*) {
        throw;
    }
}

////////////////////////////////////////////////////////////////////////////////
bool LecteurSymbole::isOpBool(char c) {
    // on verifie que la chaine et entourer du char '"'
    return (c=='=' || c=='!' || c=='<' || c=='>');
}

void LecteurSymbole::erreur ( string mess ) {
    try {
        cout << endl << "-------- Erreur ligne " << ligne << endl
             << "   Probleme  : " << mess << endl << endl;
        throw "lecture symbole";
    }
    catch (char const*) {
        throw;
    }
}
